#include "Submarine.h"

#include<iostream>
#include"StringOps.h"


using namespace std;

void Submarine::printHeading(bool bClear)
{

	if(m_bHTML)
	{
		cout<<"			<thead>" <<endl;
		cout<<"			<tr>";
	}

	int i, n=m_asOutputRow.size();
	std::string sEnd=",", sStart ="";
	if(m_bHTML) {sStart ="<th>"; sEnd = "</th>"; }

	for(i=0; i<n; i++)
	{
		if((i==n-1)&& (!m_bHTML))
			sEnd="";
		cout<<sStart<< m_asOutputRow[i]<<sEnd;
	}
	cout<<endl;

	if(m_bHTML)
	{
		cout<<"			</tr>"<<endl;
		cout<<"			</thead>"<<endl;
	}

	if(bClear) m_asOutputRow.clear();
}

void Submarine::printBodyStart()
{
	if(m_bHTML)
		cout << "			<tbody>" << endl;

}

void Submarine::printBodyEnd()
{
	if(m_bHTML)
		cout << "			</tbody>" << endl;
}

void Submarine::printElement(bool bClear)
{
	if(m_bHTML)
		cout<<"			<tr>";

	int i, n=m_asOutputRow.size();
	std::string sEnd=",", sStart ="";
	if(m_bHTML) {sStart ="<td>"; sEnd = "</td>"; }

	for(i=0; i<n; i++)
	{
		if((i==n-1)&& (!m_bHTML))
			sEnd="";
		cout<<sStart<< m_asOutputRow[i]<<sEnd;
	}
	cout<<endl;

	if(m_bHTML)
		cout<<"			</tr>"<<endl;

	if(bClear) m_asOutputRow.clear();

}

void Submarine::printFooting(bool bClear)
{
	if(m_bHTML)
	{
		cout<<"			<tfoot>"<<endl;
		cout<<"			<tr>";
	}

	int i, n=m_asOutputRow.size();
	std::string sEnd=",", sStart ="";
	if(m_bHTML) {sStart ="<td>"; sEnd = "</td>";  }

	for(i=0; i<n; i++)
	{
		if((i==n-1)&& (!m_bHTML))
			sEnd="";
		cout<<sStart<< m_asOutputRow[i]<<sEnd;
	}
	cout<<endl;

	if(m_bHTML)
	{
		cout<<"			</tr>"<<endl;
		cout<<"			</tfoot>"<<endl;
	}

	if(bClear) m_asOutputRow.clear();
}

void Submarine::outputReturns()
{
	if (!((true==m_bNoHeading)||(true==m_bReport)||(true==m_bListOnly)))
	{
		if(!m_bNoNumbering)
			m_asOutputRow.push_back("Index");
		m_asOutputRow.push_back("Function");
		m_asOutputRow.push_back("Return");
		m_asOutputRow.push_back("LineNumber");

		printHeading(false);
		printFooting();
	}

    size_t nMethods;
	size_t nReturns;
    Method* pxMethod;

    nMethods = m_pxFuncalyzer->m_apxMethod.size();

	printBodyStart();
    for(size_t nLooper=0; nLooper<nMethods; nLooper++)
    {
        pxMethod = m_pxFuncalyzer->m_apxMethod[nLooper];
        if(!pxMethod)
			//tj: May be removed IMHO. Not doing for 0.10
            continue;

		nReturns = pxMethod->m_xReturn.m_asValues.size();
		
        for(size_t i=0;i<nReturns;i++)
        {
			m_nSerialNumber++;
			if(!m_bNoNumbering)
				m_asOutputRow.push_back(stringify(m_nSerialNumber));

			m_asOutputRow.push_back(pxMethod->m_sName);
			m_asOutputRow.push_back(pxMethod->m_xReturn.m_asValues[i]); 
			m_asOutputRow.push_back(stringify(pxMethod->m_xReturn.m_anReturnPoint[i]));

			printElement();
        }
	}
	printBodyEnd();
}

void Submarine::outputCalls()
{
	if (!((true==m_bNoHeading)||(true==m_bReport)||(true==m_bListOnly)))
	{
		if(!m_bNoNumbering)
			m_asOutputRow.push_back("Index");
		m_asOutputRow.push_back("Function");
		m_asOutputRow.push_back("Calls");
		m_asOutputRow.push_back("LineNumber");

		printHeading(false);
		printFooting();

	}

    size_t nMethods = m_pxFuncalyzer->m_apxMethod.size();
    Method* pxMethod;

	printBodyStart();
	for(size_t nLooper=0;nLooper<nMethods;nLooper++)
    {
        pxMethod = m_pxFuncalyzer->m_apxMethod[nLooper];
        if(!pxMethod)
			//tj: May be removed IMHO. Not doing for 0.10
            continue;

        size_t nFuncCalls = pxMethod->m_asFunctionCall.size();
        for(size_t i=0; i< nFuncCalls; i++)
        {
			m_nSerialNumber++;
			if(!m_bNoNumbering)
				m_asOutputRow.push_back(stringify(m_nSerialNumber));
            m_asOutputRow.push_back(pxMethod->m_sName);
            m_asOutputRow.push_back(pxMethod->m_asFunctionCall[i]);
            m_asOutputRow.push_back(stringify(pxMethod->m_anFunctionCallPoint[i]));

			printElement();
        }
	}
	printBodyEnd();
}

void Submarine::outputDataUsage()
{
	if (!((true==m_bNoHeading)||(true==m_bReport)||(true==m_bListOnly)))
	{
		if(!m_bNoNumbering)
			m_asOutputRow.push_back("Index");
		m_asOutputRow.push_back("Function");
		m_asOutputRow.push_back("UsedData");
		m_asOutputRow.push_back("LineNumber");

		printHeading(false);
		printFooting();
	}

    size_t nMethods = m_pxFuncalyzer->m_apxMethod.size();
    Method* pxMethod;

	printBodyStart();
    for(size_t nLooper=0;nLooper<nMethods;nLooper++)
    {
        pxMethod = m_pxFuncalyzer->m_apxMethod[nLooper];
        if(!pxMethod)
			//tj: May be removed IMHO. Not doing for 0.10
            continue;

		size_t nFuncCalls = pxMethod->m_asDataUse.size();
        for(size_t i=0; i< nFuncCalls; i++)
        {
			m_nSerialNumber++;
			if(!m_bNoNumbering)
				m_asOutputRow.push_back(stringify(m_nSerialNumber));
            m_asOutputRow.push_back(pxMethod->m_sName);
            m_asOutputRow.push_back(pxMethod->m_asDataUse[i]);
            m_asOutputRow.push_back(stringify(pxMethod->m_anDataUsePoint[i]));

			printElement();
        }
	}
	printBodyEnd();
}

void Submarine::outputComplexity()
{
	if (!((true==m_bNoHeading)||(true==m_bReport)||(true==m_bListOnly)))
	{
		if(!m_bNoNumbering)
			m_asOutputRow.push_back("Index");
		m_asOutputRow.push_back("Name");
		m_asOutputRow.push_back("Nesting");
		m_asOutputRow.push_back("Exits");
		m_asOutputRow.push_back("Statements");
		m_asOutputRow.push_back("LoC");
		m_asOutputRow.push_back("Comments");
		m_asOutputRow.push_back("Paths");
		m_asOutputRow.push_back("Type");
		m_asOutputRow.push_back("Arguments");
		m_asOutputRow.push_back("Line");

		printHeading(false);
		printFooting();
	}

    size_t nMethods = m_pxFuncalyzer->m_apxMethod.size();
    size_t nArguments;
    Method* pxMethod;

	printBodyStart();
    for(size_t nLooper=0;nLooper<nMethods;nLooper++)
    {
        pxMethod = m_pxFuncalyzer->m_apxMethod[nLooper];
        if(!pxMethod)
			//tj: May be removed IMHO. Not doing for 0.10
            continue;

		m_nSerialNumber++;

		nArguments = pxMethod->m_axArguments.size();
		if(m_bReport) 
		{
			cout<< "Function:("<<m_nSerialNumber<<")"<<endl;
			cout<< "Name:"<<pxMethod->m_sName<<endl;
			cout<< "Defined:"<<pxMethod->m_nDefinePoint<<endl;
			cout<< "Type:"<<pxMethod->m_xReturn.m_sType<<endl;
			cout<< "Arguments:"<<nArguments<<endl;
			for(size_t nArgLooper=0;nArgLooper<nArguments;nArgLooper++)
			{
				cout<<"\t(";
				cout<<pxMethod->m_axArguments[nArgLooper].m_sName<<":";
				cout<<pxMethod->m_axArguments[nArgLooper].m_sTypePrefix;
				cout<<")"<<endl;
			}

			cout<< "Complexity:"<<endl;
			cout<< "\tNesting="<<pxMethod->m_xComplexity.m_nMaxDepth<<endl;
			cout<< "\tReturn Points="<<pxMethod->m_xReturn.m_anReturnPoint.size()<<endl;
			cout<< "\tStatements="<<pxMethod->m_xComplexity.m_nStatements<<endl;
			cout<< "\tLines of Code="<<pxMethod->m_xComplexity.m_nLoC<<endl;
			cout<< "\tLines of Comments="<<pxMethod->m_xComplexity.m_nLoCom<<endl;
			cout<< "\tExecutionPaths="<<pxMethod->m_xComplexity.m_nPaths<<endl;
			cout<< "Summary:";
		}

		if(!m_bNoNumbering)
			m_asOutputRow.push_back(stringify(m_nSerialNumber));;
		m_asOutputRow.push_back(pxMethod->m_sName);
        if(m_bListOnly)
		{
			printElement();
			continue;
		}

        m_asOutputRow.push_back(stringify(pxMethod->m_xComplexity.m_nMaxDepth));
		m_asOutputRow.push_back(stringify(pxMethod->m_xReturn.m_anReturnPoint.size()));
        m_asOutputRow.push_back(stringify(pxMethod->m_xComplexity.m_nStatements));
        m_asOutputRow.push_back(stringify(pxMethod->m_xComplexity.m_nLoC));
        m_asOutputRow.push_back(stringify(pxMethod->m_xComplexity.m_nLoCom));
        m_asOutputRow.push_back(stringify(pxMethod->m_xComplexity.m_nPaths));
        m_asOutputRow.push_back(pxMethod->m_xReturn.m_sType);
		m_asOutputRow.push_back(stringify(pxMethod->m_axArguments.size()));
		m_asOutputRow.push_back(stringify(pxMethod->m_nDefinePoint));

		printElement();

		if(m_bReport)
			cout<<endl;
    }
	printBodyEnd();
}

void Submarine::print()
{
	if(m_bHTML)
	{
		cout <<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"<<endl;
		cout <<"<html>"<<endl;
		cout <<"<head>"<<endl;
		cout <<"		<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"style.css\" />"<<endl;
		cout <<"		<script type=\"text/javascript\" src=\"prototype.js\"></script>"<<endl;
		cout <<"		<script type=\"text/javascript\" src=\"fastinit.js\"></script>"<<endl;
		cout <<"		<script type=\"text/javascript\" src=\"tablesort.js\"></script>"<<endl;
		cout <<"	</head>"<<endl;
		cout <<"	<body>"<<endl;
	}

	if(m_bHTML)
	{
		cout<<"			<table class=\"sortable\">" <<endl;
	}
	if( (m_bCalls==false) && (m_bReturns ==false) && (m_bDataUse == false))
		m_bComplexity = true;

	if(m_bComplexity)
		outputComplexity();
	else 
	{
		if(m_bCalls)
			outputCalls();
		else if(m_bReturns)
			outputReturns();
		else if(m_bDataUse)
			outputDataUsage();
	}


	if(m_bHTML)
	{
		cout<<"			</table>"<<endl;
	}

	if(m_bHTML)
	{
		cout<<"	</body>"<<endl;
		cout<<"</html>"<<endl;
	}
}


